package market

import (
	"bytes"
	"crypto/tls"
	"database/sql"
	"fmt"
	"log"
	"net"
	"net/smtp"
	"text/template"

	"github.com/spf13/viper"
)

type MarketingEmailRequest struct {
	Subject   string `json:"subject" binding:"required"`
	Content   string `json:"content" binding:"required"`
	IsTest    bool   `json:"is_test"`
	TestEmail string `json:"test_email"`
}

type MarketingPreference struct {
	UserID         int  `json:"user_id"`
	EmailMarketing bool `json:"email_marketing"`
}

type MarketingEmailLog struct {
	ID             int    `json:"id"`
	Subject        string `json:"subject"`
	Content        string `json:"content"`
	SenderID       int    `json:"sender_id"`
	TotalSent      int    `json:"total_sent"`
	SuccessfulSent int    `json:"successful_sent"`
	FailedSent     int    `json:"failed_sent"`
	CreatedAt      string `json:"created_at"`
}

func InitMarketingClient() {
	log.Println("Marketing email client initialized")
}

func SendMarketingMail(to string, subject string, content string) error {
	return SendMarketingMailWithName(to, subject, content, "用户")
}

func SendMarketingMailWithName(to string, subject string, content string, name string) error {
	return SendMarketingMailWithTemplate(to, subject, "marketing.html", map[string]interface{}{
		"Subject":        subject,
		"Content":        content,
		"Name":           name,
		"UnsubscribeUrl": "https://deeptrain.net/home/market",
	})
}

func Dial(addr string) (*smtp.Client, error) {
	conn, err := tls.Dial("tcp", addr, nil)
	if err != nil {
		return nil, err
	}
	host, _, _ := net.SplitHostPort(addr)
	return smtp.NewClient(conn, host)
}

func formatMarketingMail(headers map[string]string, body string) (result string) {
	for k, v := range headers {
		result += fmt.Sprintf("%s: %s\r\n", k, v)
	}
	return fmt.Sprintf("%s\r\n%s", result, body)
}

func sendMarketingMailWithTLS(addr string, auth smtp.Auth, from string, to []string, msg []byte) error {
	client, err := Dial(addr)
	if err != nil {
		return err
	}
	defer client.Close()

	if auth != nil {
		if ok, _ := client.Extension("AUTH"); ok {
			if err = client.Auth(auth); err != nil {
				return err
			}
		}
	}

	if err = client.Mail(from); err != nil {
		return err
	}

	for _, addr := range to {
		if err = client.Rcpt(addr); err != nil {
			return err
		}
	}

	writer, err := client.Data()
	if err != nil {
		return err
	}

	if _, err = writer.Write(msg); err != nil {
		return err
	}

	if err = writer.Close(); err != nil {
		return err
	}

	return client.Quit()
}

func SendMarketingMailWithTemplate(to string, subject string, templateName string, data interface{}) error {
	tmpl, err := template.New(templateName).ParseFiles(fmt.Sprintf("market/templates/%s", templateName))
	if err != nil {
		return err
	}

	var buf bytes.Buffer
	err = tmpl.ExecuteTemplate(&buf, templateName, data)
	if err != nil {
		return err
	}

	addr := fmt.Sprintf("%s:%d", viper.GetString("marketing.smtp.host"), viper.GetInt("marketing.smtp.port"))
	auth := smtp.PlainAuth("", viper.GetString("marketing.smtp.from"), viper.GetString("marketing.smtp.password"), viper.GetString("marketing.smtp.host"))

	err = sendMarketingMailWithTLS(addr, auth, viper.GetString("marketing.smtp.from"), []string{to},
		[]byte(formatMarketingMail(map[string]string{
			"From":         fmt.Sprintf("%s <%s>", viper.GetString("marketing.smtp.username"), viper.GetString("marketing.smtp.from")),
			"To":           to,
			"Subject":      subject,
			"Content-Type": "text/html; charset=utf-8",
		}, buf.String())))

	return err
}

type MarketingUser struct {
	ID          int    `json:"id"`
	Username    string `json:"username"`
	Email       string `json:"email"`
	DisplayName string `json:"display_name"`
	Active      bool   `json:"active"`
	IsAdmin     bool   `json:"is_admin"`
}

func GetUsersForMarketing(db *sql.DB) ([]MarketingUser, error) {
	rows, err := db.Query(`
		SELECT a.id, a.username, a.email, a.username as display_name, a.active, a.is_admin 
		FROM auth a 
		LEFT JOIN marketing_preferences mp ON a.id = mp.user_id
		WHERE a.active = TRUE AND (mp.email_marketing = TRUE OR mp.email_marketing IS NULL)
	`)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var users []MarketingUser
	for rows.Next() {
		var user MarketingUser
		err := rows.Scan(&user.ID, &user.Username, &user.Email, &user.DisplayName, &user.Active, &user.IsAdmin)
		if err != nil {
			return nil, err
		}
		users = append(users, user)
	}

	return users, nil
}

func GetMarketingPreference(db *sql.DB, userID int) (*MarketingPreference, error) {
	var pref MarketingPreference
	err := db.QueryRow(`
		SELECT user_id, email_marketing 
		FROM marketing_preferences 
		WHERE user_id = ?
	`, userID).Scan(&pref.UserID, &pref.EmailMarketing)

	if err != nil {
		if err == sql.ErrNoRows {
			return &MarketingPreference{
				UserID:         userID,
				EmailMarketing: false,
			}, nil
		}
		return nil, err
	}

	return &pref, nil
}

func SetMarketingPreference(db *sql.DB, userID int, emailMarketing bool) error {
	_, err := db.Exec(`
		INSERT INTO marketing_preferences (user_id, email_marketing) 
		VALUES (?, ?) 
		ON DUPLICATE KEY UPDATE 
		email_marketing = VALUES(email_marketing), 
		updated_at = CURRENT_TIMESTAMP
	`, userID, emailMarketing)

	return err
}

func LogMarketingEmail(db *sql.DB, subject, content string, senderID int) (int, error) {
	result, err := db.Exec(`
		INSERT INTO marketing_email_log (subject, content, sender_id) 
		VALUES (?, ?, ?)
	`, subject, content, senderID)

	if err != nil {
		return 0, err
	}

	id, err := result.LastInsertId()
	if err != nil {
		return 0, err
	}

	return int(id), nil
}

func UpdateMarketingEmailStats(db *sql.DB, emailID, totalSent, successfulSent, failedSent int) error {
	_, err := db.Exec(`
		UPDATE marketing_email_log 
		SET total_sent = ?, successful_sent = ?, failed_sent = ? 
		WHERE id = ?
	`, totalSent, successfulSent, failedSent, emailID)

	return err
}

func LogMarketingEmailRecipient(db *sql.DB, emailID, userID int, email, status, errorMessage string) error {
	_, err := db.Exec(`
		INSERT INTO marketing_email_recipients (marketing_email_id, user_id, email, status, sent_at, error_message) 
		VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP, ?)
	`, emailID, userID, email, status, errorMessage)

	return err
}
